package com.mg.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.mg.common.exception.MGExceptionEnum;
import com.mg.common.exception.ServiceException;
import com.mg.common.utils.BeanUtil;
import com.mg.common.utils.CodeUtils;
import com.mg.common.vo.ResponsePageResult;
import com.mg.order.mapper.*;
import com.mg.order.pojo.dto.RequestOrderBody;
import com.mg.order.pojo.po.OrderDetailPo;
import com.mg.order.pojo.po.OrderPo;
import com.mg.order.pojo.po.PromotionPo;
import com.mg.order.pojo.po.SkuPo;
import com.mg.order.pojo.vo.ResponseOrderDetailVo;
import com.mg.order.pojo.vo.ResponseOrderVo;
import com.mg.order.service.OrderService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.dozer.DozerBeanMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDetailMapper detailMapper;
    @Autowired
    private StockMapper stockMapper;
    @Autowired
    private SkuMapper skuMapper;
    @Autowired
    private PromotionMapper promotionMapper;
    @Autowired
    private DozerBeanMapper dozerBeanMapper;

    /**
     * 生成订单
     * 按数据量小先插入原则
     *
     * @param orderBody
     * @return
     */
    @Override
    @Transactional
    public Long genarate(RequestOrderBody orderBody) {
        int res;
        //类型转换
        OrderPo orderPo = dozerBeanMapper.map(orderBody.getOrderDto(), OrderPo.class);
        List<OrderDetailPo> orderDetailPoList = BeanUtil.beanMapper(orderBody.getOrderDetailDtoList(), new TypeReference<List<OrderDetailPo>>() {
        });
        //生成订单id
        Long orderId = CodeUtils.generateNumberId();
        //创建订单
        //获取map<skuId,num>
        Map<Long, Integer> map = orderDetailPoList.stream().collect(Collectors.toMap(OrderDetailPo::getSkuId, OrderDetailPo::getNum));
        //根据skuId减库存
        map.forEach((skuId, num) -> {
            //1.减库存,增销量
            if (1 != stockMapper.stockSell(num, skuId)) {
                //有一个失败,抛异常
                throw new ServiceException(MGExceptionEnum.STOCK__NOT_ENOUGH);
            }
        });

        //2.成功,查询商品信息
        Set<Long> skuIds = map.keySet();
        List<SkuPo> skus = skuMapper.selectBatchIds(skuIds);
        //2.1查不到获取数量缺失,抛异常
        if (null == skus || skus.size() < orderDetailPoList.size()) {
            throw new ServiceException(MGExceptionEnum.PRODUCE_INVALID);
        }
        //3.是否有优惠价,优惠卷是否有效
        long discount = 0;
        if (StringUtils.isNotBlank(orderPo.getPromotionIds())) {
            PromotionPo promotionPo = new PromotionPo(orderPo.getPromotionIds(), orderPo.getUserId());
            UpdateWrapper<PromotionPo> updateWrapper = new UpdateWrapper<>();
            discount= orderBody.getOrderDto().getQuota();
            updateWrapper
                    .set("status",PromotionPo.INVALID_STATUS)
                    .eq("id", orderPo.getPromotionIds())
                    .eq("uid", orderPo.getUserId())
                    .eq("status", PromotionPo.VALID_STATUS)
                    .eq("quota",discount);
            res = promotionMapper.update(promotionPo, updateWrapper);
            //优惠券信息错误,抛异常
            if (res != 1) {
                throw new ServiceException(MGExceptionEnum.COUPON_VALID);
            }

        }
        //计算总金额
        AtomicReference<Long> total = new AtomicReference<>(0L);
        //4.优惠卷有效,设置订单详情
        List<OrderDetailPo> orderDetailPos = new ArrayList<>();
        //封装订单项,并加入list&并计算总价
        skus.parallelStream().forEach(skuPo -> {
            orderDetailPos.add(
                    new OrderDetailPo(orderId, skuPo.getId()
                            , map.get(skuPo.getId()), skuPo.getTitle()
                            , skuPo.getOwnSpec(), skuPo.getPrice()
                            , skuPo.getImages())
            );
            //计算总金额
            total.updateAndGet(v -> v + skuPo.getPrice());
        });
        //若有失败抛异常
        if (orderDetailPos.size() != skus.size()) {
            throw new ServiceException(MGExceptionEnum.UNKNOWN_ERROR);
        }
        //全部封装成功 批量存入
        res = detailMapper.insertBatch(orderDetailPos);
        //有插入失败,抛异常
        if (res != orderDetailPos.size()) {
            throw new ServiceException(MGExceptionEnum.GENERATE_ORDER_DETAIL_FAIL);
        }
        //封装订单信息
        Long totalPay = total.get();
        orderPo.setOrderId(orderId);
        orderPo.setActualPay(totalPay - discount);
        orderPo.setTotalPay(totalPay);
        //插入订单信息
        res = orderMapper.insert(orderPo);
        //失败抛异常
        if (res != 1) {
            throw new ServiceException(MGExceptionEnum.GENERATE_ORDER_FAIL);
        }
        return orderId;
    }

    @Override
    public ResponsePageResult<List<ResponseOrderVo>> getPage(Integer curr, Integer size, Long userId) {
        //查询订单表
        QueryWrapper<OrderPo> queryWrapper = new QueryWrapper<>();
        List<OrderPo> orderPos = orderMapper.selectPageByUid(userId, curr * size, size);
        //订单表校验
        if (CollectionUtils.isEmpty(orderPos)){return null;}
        //类型转换
        List<ResponseOrderVo> orderVoList = BeanUtil.beanMapper(orderPos, new TypeReference<List<ResponseOrderVo>>() {
        });
        //转换结果校验
        if (orderVoList.size()!=orderVoList.size()){throw new ServiceException(MGExceptionEnum.PARSE_ERROR);}
        //查询所有订单表详情
        orderVoList.forEach(order->{
            List<OrderDetailPo> orderDetailPoList = detailMapper.getDetailsByOrderId(order.getOrderId());
            List<ResponseOrderDetailVo> orderDetailVos = BeanUtil.beanMapper(orderDetailPoList, new TypeReference<List<ResponseOrderDetailVo>>() {
            });
            //非空校验
            if (CollectionUtils.isEmpty(orderDetailVos)){throw new ServiceException(MGExceptionEnum.FOUND_ORDER_BUT_NOT_DETAILS);}
               order.setDetailVoList(orderDetailVos);
        });
        //返回封装结果集
        return ResponsePageResult.page(orderVoList);
    }

}
